package com.funi;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**********************************************************************
 * &lt;p&gt;文件名：EnhancedFileLineCounter.java &lt;/p&gt;
 * &lt;p&gt;文件描述：(描述该文件做什么) 
 * @project_name：code_total
 * @author zengshunyao
 * @create 2025/9/2 12:06
 * @history
 * @department：政务事业部
 * Copyright ChengDu Funi Cloud Code Technology Development CO.,LTD 2014 
 *                    All Rights Reserved.
 */

/**
 * 目录文件行数统计工具（增强版）
 * 功能：递归扫描指定目录及子目录下指定后缀的文件，排除指定目录，并计算总行数
 * 特别适用于工程项目文件统计（如高速公路工程设计图纸项目）
 */
public class EnhancedFileLineCounter {

    public static void main(String[] args) {
        // 设置要扫描的目录路径
        // 预售资金
        //后端
        final String directoryPath = "/Users/apple/work/funi/gitlab_software_park/funi-platform-cdpsfs-web/src/main";
        //js 等静态资源
        //String directoryPath = "/Users/apple/work/funi/gitlab_software_park/funi-platform-cdpsfs-web/src/main/webapp/app/platform/cdpsfs";


        //存量房资金监管(老) 仅java+xml
        //final String directoryPath = "/Users/apple/work/funi/gitlab/funi-platform-shfs/src/main";
        //存量房资金监管(新) 仅java+xml
        //final String directoryPath = "/Users/apple/work/funi/gitlab_software_park/funi-cloud-lfsg/funi-cloud-lfsg-application/src/main";

        // 设置要统计的文件后缀
        final String[] suffixes = {".java", ".xml", ".properties", ".txt", ".js"}; // 可添加工程图纸相关后缀  , ".dwg", ".pdf"

        // 设置要排除的目录（常见工程目录和系统目录）
        final String[] excludeDirs = {
                "node_modules",      // Node.js依赖目录
                "target", "build",   // 构建输出目录
                ".git", ".svn",      // 版本控制目录
                "bin", "obj",        // 编译输出目录
                "logs", "temp",      // 日志和临时目录
                "backup", "archive"  // 备份和归档目录
                //, "webapp"           //webapp
        };

        try {
            System.out.println("开始统计工程目录: " + directoryPath);
            System.out.println("目标文件类型: " + String.join(", ", suffixes));
            System.out.println("排除目录: " + String.join(", ", excludeDirs));
            System.out.println("----------------------------------------");

            // 执行统计
            final long totalLines = countFilesLines(directoryPath, suffixes, excludeDirs);

            System.out.println("----------------------------------------");
            System.out.println("统计完成！总行数: " + totalLines);
            System.out.println("注：已自动排除常见工程无关目录，确保统计准确性");

        } catch (Exception e) {
            System.err.println("执行过程中出现错误: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 递归统计指定目录下特定后缀文件的行数，排除指定目录
     *
     * @param directoryPath 目录路径
     * @param suffixes      文件后缀数组
     * @param excludeDirs   要排除的目录名称数组
     * @return 总行数
     */
    private static long countFilesLines(String directoryPath, String[] suffixes, String[] excludeDirs) {
        final List<File> fileList = new ArrayList<>();
        final AtomicLong totalLines = new AtomicLong(0);

        // 查找所有指定后缀的文件（排除指定目录）
        findFilesBySuffix(new File(directoryPath), suffixes, excludeDirs, fileList);

        // 统计文件行数
        fileList.forEach(file -> {
            try {
                long lineCount = countSingleFileLines(file);
                totalLines.addAndGet(lineCount);
                // 输出每个文件的统计结果
                System.out.println(file.getAbsolutePath() + " --> 行数: " + lineCount);
            } catch (IOException e) {
                System.err.println("无法读取文件: " + file.getAbsolutePath() + ", 错误: " + e.getMessage());
            }
        });

        return totalLines.get();
    }

    /**
     * 递归查找指定后缀的文件，排除指定目录
     *
     * @param directory   要查找的目录
     * @param suffixes    文件后缀数组
     * @param excludeDirs 要排除的目录名称数组
     * @param fileList    存储匹配文件的列表
     */
    private static void findFilesBySuffix(File directory, String[] suffixes, String[] excludeDirs, List<File> fileList) {
        if (directory == null || !directory.exists() || !directory.isDirectory()) {
            System.err.println("目录不存在或不是有效目录: " + directory);
            return;
        }

        // 检查当前目录是否在排除列表中
        if (shouldExclude(directory, excludeDirs)) {
            System.out.println("跳过排除目录: " + directory.getAbsolutePath());
            return;
        }

        final File[] files = directory.listFiles();
        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                // 递归遍历子目录（自动应用排除规则）
                findFilesBySuffix(file, suffixes, excludeDirs, fileList);
            } else {
                // 检查文件后缀是否匹配
                for (String suffix : suffixes) {
                    if (file.getName().toLowerCase().endsWith(suffix.toLowerCase())) {
                        fileList.add(file);
                        break;
                    }
                }
            }
        }
    }

    /**
     * 判断目录是否应该被排除
     *
     * @param directory   要检查的目录
     * @param excludeDirs 排除目录名称数组
     * @return 是否排除
     */
    private static boolean shouldExclude(File directory, String[] excludeDirs) {
        final String dirName = directory.getName();
        for (String excludeDir : excludeDirs) {
            if (dirName.equalsIgnoreCase(excludeDir)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 统计单个文件的行数
     *
     * @param file 要统计的文件
     * @return 文件行数
     * @throws IOException 当文件读取失败时抛出
     */
    private static long countSingleFileLines(File file) throws IOException {
        long lineCount = 0;

        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            while (reader.readLine() != null) {
                lineCount++;
            }
        }

        return lineCount;
    }

    /**
     * 获取默认排除目录列表（适用于工程项目）
     *
     * @return 默认排除目录数组
     */
    public static String[] getDefaultExcludeDirs() {
        return new String[]{
                "node_modules", "target", "build", "dist", "out",
                ".git", ".svn", ".idea", "bin", "obj",
                "logs", "temp", "tmp", "backup", "archive",
                "vendor", "dependencies", "libs"
        };
    }
}
